/**
 * 
 */
package org.vsg.stock.basic.service.handler;

import java.util.Iterator;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vsg.common.biz.exception.ServiceException;
import org.vsg.stock.basic.domain.StockDayIndicator;
import org.vsg.stock.basic.domain.StockTick;

/**
 * @author vison
 *
 */
public class StandardAvalysisTickHandler implements AnalysisTickHandler {
	
	private double bigQuotient = 9.5;
	
	private double midQuotient = 4.5;

	/**
	 * set the logger for developer code , do not use System.print(ln) to out print message.
	 */
	private static final Logger logger = LoggerFactory.getLogger(StandardAvalysisTickHandler.class);
	

	private List<TradeTickNatureHandler> tickNatureHandlers;

	public List<TradeTickNatureHandler> getTickNatureHandlers() {
		return tickNatureHandlers;
	}

	public void setTickNatureHandlers(
			List<TradeTickNatureHandler> tickNatureHandlers) {
		this.tickNatureHandlers = tickNatureHandlers;
	}

	/* (non-Javadoc)
	 * @see org.vsg.stock.basic.service.AnalysisTickHandler#analyseTicks(org.vsg.stock.basic.domain.StockDayIndicator, java.util.List)
	 */
	@Override
	public StockDayIndicator analyseTicks(StockDayIndicator indicator,
			List<StockTick> stockTickList) throws ServiceException {
		// TODO Auto-generated method stub

		double bBigOrdLevel = indicator.getAverageTick() * bigQuotient; 
		double midBigOrdLevel = indicator.getAverageTick() * midQuotient;	
		
		
		long retailBuyVol = 0;
		long retailSellVol = 0;
		long middleBuyVol = 0; 
		long middleSellVol = 0;
		long mainBuyVol  = 0;
		long mainSellVol  = 0;
		double retailBuyAmount = 0;
		double retailSellAmount = 0;
		double middleBuyAmount = 0; 
		double middleSellAmount = 0;
		double mainBuyAmount  = 0;
		double mainSellAmount  = 0;		
		long matchOrderBuyVol  = 0;
		long matchOrderSellVol = 0;
		double matchOrderBuyAmount  = 0;
		double matchOrderSellAmount  = 0;		
		


		// --- scan stock tick list ---
		StockTick stockTick = null;
		Object[] matchOrderRef = null;
		for (int i = 0 ; i < stockTickList.size() ; i++) {
			stockTick = stockTickList.get(i);
			//--- handle logic ---
			
			if (stockTick.getTickType().equals("buy")) {
				
				if (stockTick.getPresentTickVol() >= bBigOrdLevel) {
					mainBuyVol+=stockTick.getPresentTickVol();
					mainBuyAmount+=stockTick.getPresentTickVol() * stockTick.getLastCurrentPrice();
					matchOrderRef = checkOrderNature( indicator , stockTickList , i , bBigOrdLevel , midBigOrdLevel );
					if (matchOrderRef != null) {
						long vol = (Long)matchOrderRef[0];
						double amount = (Double)matchOrderRef[1];
						if (vol > 0) {
							matchOrderBuyVol+=vol;
							matchOrderBuyAmount+= amount;
						} else {
							matchOrderSellVol+=Math.abs( vol );
							matchOrderSellAmount+= Math.abs( amount );
						}
					}
				} else if (stockTick.getPresentTickVol() < bBigOrdLevel 
						&& stockTick.getPresentTickVol() >= midBigOrdLevel) {
					middleBuyVol+=stockTick.getPresentTickVol();
					middleBuyAmount+=stockTick.getPresentTickVol() * stockTick.getLastCurrentPrice();
					matchOrderRef = checkOrderNature(  indicator , stockTickList , i , bBigOrdLevel , midBigOrdLevel );
					if (matchOrderRef != null) {
						long vol = (Long)matchOrderRef[0];
						double amount = (Double)matchOrderRef[1];
						if (vol > 0) {
							matchOrderBuyVol+=vol;
							matchOrderBuyAmount+= amount;
						} else {
							matchOrderSellVol+=Math.abs( vol );
							matchOrderSellAmount+= Math.abs(amount );
						}
					}

				} else {
					retailBuyVol+=stockTick.getPresentTickVol();
					retailBuyAmount+=stockTick.getPresentTickVol() * stockTick.getLastCurrentPrice();
				}
				
			}
			else if (stockTick.getTickType().equals("sell")) {
				if (stockTick.getPresentTickVol() >= bBigOrdLevel) {
					mainSellVol+=stockTick.getPresentTickVol();
					mainSellAmount+=stockTick.getPresentTickVol() * stockTick.getLastCurrentPrice();
					matchOrderRef = checkOrderNature(  indicator , stockTickList , i , bBigOrdLevel , midBigOrdLevel );
					if (matchOrderRef != null) {
						long vol = (Long)matchOrderRef[0];
						double amount = (Double)matchOrderRef[1];
						if (vol > 0) {
							matchOrderBuyVol+=vol;
							matchOrderBuyAmount+= amount;
						} else {
							matchOrderSellVol+=Math.abs( vol );
							matchOrderSellAmount+= Math.abs(amount );
						}
					}

				} else if (stockTick.getPresentTickVol() < bBigOrdLevel 
						&& stockTick.getPresentTickVol() >= midBigOrdLevel) {
					middleSellVol+=stockTick.getPresentTickVol();
					middleSellAmount+=stockTick.getPresentTickVol() * stockTick.getLastCurrentPrice();
					matchOrderRef = checkOrderNature( indicator , stockTickList , i , bBigOrdLevel , midBigOrdLevel );
					if (matchOrderRef != null) {
						long vol = (Long)matchOrderRef[0];
						double amount = (Double)matchOrderRef[1];
						if (vol > 0) {
							matchOrderBuyVol+=vol;
							matchOrderBuyAmount+= amount;
						} else {
							matchOrderSellVol+=Math.abs( vol );
							matchOrderSellAmount+= Math.abs(amount );
						}
					}

				} else {
					retailSellVol+=stockTick.getPresentTickVol();
					retailSellAmount+=stockTick.getPresentTickVol() * stockTick.getLastCurrentPrice();
				}				
			}
			

		}
		
		
		// --- update entity property ---
		indicator.setRetailBuyVol( retailBuyVol);
		indicator.setRetailSellVol( retailSellVol );
		indicator.setMiddleBuyVol( middleBuyVol );
		indicator.setMiddleSellVol( middleSellVol );
		indicator.setBigBuyVol( mainBuyVol );
		indicator.setBigSellVol( mainSellVol );
		

		indicator.setRetailBuyAmount( retailBuyAmount );
		indicator.setRetailSellAmount( retailSellAmount );
		indicator.setMiddleBuyAmount( middleBuyAmount );
		indicator.setMiddleSellAmount( middleSellAmount );
		indicator.setMainBuyAmount( mainBuyAmount );
		indicator.setMainSellAmount( mainSellAmount );
		
		indicator.setMatchOrderBuyVol( matchOrderBuyVol );
		indicator.setMatchOrderBuyAmount( matchOrderBuyAmount );
		indicator.setMatchOrderSellVol( matchOrderSellVol );
		indicator.setMatchOrderSellAmount( matchOrderSellAmount );
	
		return indicator;
	}
	
	private Object[] checkOrderNature(
			StockDayIndicator indicator,
			List<StockTick> stockTickList,
			int index,
			double bBigOrdLevel,
			double midBigOrdLevel
		) {
		
		Object[] resultObj = null;

		short result = 0;
		TradeTickNatureHandler handle = null;
		for (Iterator<TradeTickNatureHandler> handlersIter = tickNatureHandlers.iterator() ; handlersIter.hasNext() ; ) {
			handle = handlersIter.next();
			result = handle.handle(indicator, stockTickList, index, bBigOrdLevel, midBigOrdLevel);

			if (result != TradeTickNatureHandler.SKIP) {
				resultObj = new Object[2];
				resultObj[0] = new Long(handle.getVol());
				resultObj[1] = new Double(handle.getAmount());
				break;
			}
		}
		
		if (result == 0) {
			// --- un check the stock handle ---
			logger.info("unknow ticknature code: ["+indicator.getStockCode()+"] " + stockTickList.get(index).getDateTime());
		}
		
		
		return resultObj;
	}

}
